package org.hcyspartnoc.luoxin.controller.common;

import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wf.captcha.ArithmeticCaptcha;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.hcyspartnoc.luoxin.common.core.AjaxResult;
import org.hcyspartnoc.luoxin.common.core.annotation.Log;
import org.hcyspartnoc.luoxin.common.core.annotation.PreAuthorize;
import org.hcyspartnoc.luoxin.common.core.configuration.UtilsConfiguration;
import org.hcyspartnoc.luoxin.common.core.configuration.WeiXinConfiguration;
import org.hcyspartnoc.luoxin.common.core.enums.BusinessType;
import org.hcyspartnoc.luoxin.common.enums.service.OrderTypeEnum;
import org.hcyspartnoc.luoxin.common.enums.service.ServiceCounselorStatusEnum;
import org.hcyspartnoc.luoxin.common.exception.common.CommonUtilsException;
import org.hcyspartnoc.luoxin.common.exception.service.ServiceCounselorOrderException;
import org.hcyspartnoc.luoxin.mapper.service.ServiceCounselorOrderMapper;
import org.hcyspartnoc.luoxin.mapper.system.SysUserMapper;
import org.hcyspartnoc.luoxin.pojo.dto.common.CommonSttDto;
import org.hcyspartnoc.luoxin.pojo.po.service.ServiceCounselorOrderPo;
import org.hcyspartnoc.luoxin.utils.AliyunOssUtils;
import org.hcyspartnoc.luoxin.utils.MultimediaUtils;
import org.hcyspartnoc.luoxin.utils.StringUtils;
import org.hcyspartnoc.luoxin.utils.redis.RedisComponent;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;

@RestController
@RequestMapping("/common/utils")
public class CommonUtilsController {
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private AliyunOssUtils aliyunOssUtils;
    @Resource
    private WeiXinConfiguration weiXinConfiguration;
    @Resource
    private ServiceCounselorOrderMapper serviceCounselorOrderMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private UtilsConfiguration utilsConfiguration;

    @Log(title = "通用·工具·图形验证码", businessType = BusinessType.OTHER, isSaveResponseData = false)
    @PreAuthorize(auth = "common:utils:captcha:image", descr = "获取图形验证码")
    @GetMapping("/captcha/image")
    public AjaxResult captchaByImage() {
        // 每分钟访问次数限制 TODO
        //生成验证码
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(utilsConfiguration.getCaptcha().getImageWidth(), utilsConfiguration.getCaptcha().getImageHeight(), 3); // 宽度、高度、运算的位数
        String verCode = captcha.text();
        String key = UUID.randomUUID().toString();
        redisComponent.setImageCaptcha(key, verCode);
        HashMap<String, String> result = new HashMap<>();
        result.put("captchaKey", key);
        result.put("captchaBase64", captcha.toBase64());
        return AjaxResult.success(result);
    }

    @Log(title = "通用·工具·上传·图片", businessType = BusinessType.INSERT)
    @PreAuthorize(auth = "common:utils:upload:image", descr = "上传图片")
    @PostMapping("/upload/image")
    public AjaxResult uploadImage(@NotNull @RequestParam MultipartFile file) throws CommonUtilsException {
        try {
            // 验证是否是图片资源 TODO
            // 验证是否是图片资源
            // 获取文件的 MIME 类型
            String contentType = file.getContentType();
            if (Objects.isNull(contentType) || !contentType.startsWith("image/")) {
                throw new CommonUtilsException(CommonUtilsException.SRC_NOT_RIGHT);
            }
            //获取原始的文件名
            String originalFilename = file.getOriginalFilename();
            if (Objects.isNull(originalFilename))
                throw new CommonUtilsException(CommonUtilsException.SRC_NOT_RIGHT);
            //在oss中存储名字就是UUID + 文件的后缀名
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            if (!utilsConfiguration.getFile().getAllowedImageTypes().contains(fileExtension.toUpperCase()))
                throw new CommonUtilsException(CommonUtilsException.SRC_NOT_RIGHT);
            String objectName = UUID.randomUUID() + "." + fileExtension;
            String resultURL = aliyunOssUtils.upload(file.getBytes(), objectName);
            HashMap<String, String> result = new HashMap<>();
            result.put("url", resultURL);
            result.put("name", objectName);
            return AjaxResult.success(result);
        } catch (IOException e) {
            throw new CommonUtilsException(CommonUtilsException.SRC_UPLOAD_FAIL);
        }
    }

    @Log(title = "通用·工具·STT", businessType = BusinessType.OTHER, isSaveRequestData = false, isSaveResponseData = false)
    @PreAuthorize(auth = "common:utils:stt", descr = "通用语音转文本")
    @PostMapping("/stt")
    public AjaxResult stt(@Valid @RequestBody CommonSttDto commonSttDto) throws CommonUtilsException {
        String text = MultimediaUtils.base64ToText(commonSttDto.getWavBase64Audio());
        if (Objects.isNull(text) || text.isEmpty())
            throw new CommonUtilsException(CommonUtilsException.AUDIO_PARSE_FAIL);
        return AjaxResult.success(text);
    }

    @Log(title = "通用·工具·支付回调", businessType = BusinessType.OTHER)
    @PreAuthorize(auth = "service:cOrder:payNotify:wx", descr = "微信订单支付回调")
    @PostMapping("/payNotify")
    public AjaxResult payNotify(HttpServletRequest request) throws ServiceCounselorOrderException {
        //注意：回调接口需要暴露到公网上，且要放开token验证
        BufferedReader bufferedReader = null;
        try {
            // 读取请求体的信息
            ServletInputStream inputStream = request.getInputStream();
            StringBuilder stringBuilder = new StringBuilder();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line;

            // 读取回调请求体
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
            }
            // 获取请求体内容
            String body = stringBuilder.toString();

            // 获取请求头部信息
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String signType = request.getHeader("Wechatpay-Signature-Type");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            // 构造 RSAAutoCertificateConfig
            NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(weiXinConfiguration.getMch().getId())
                    .privateKeyFromPath(weiXinConfiguration.getMch().getKeyPath())
                    .merchantSerialNumber(weiXinConfiguration.getMch().getSerialNo())
                    .apiV3Key(weiXinConfiguration.getMch().getApiKey())
                    .build();

            // 初始化 NotificationParser
            NotificationParser parser = new NotificationParser(config);

            // 构造 RequestParam
            com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
                    .serialNumber(serialNo)
                    .nonce(nonce)
                    .signature(signature)
                    .timestamp(timestamp)
                    .signType(signType)  // 若未设置 signType，默认值为 WECHATPAY2-SHA256-RSA2048
                    .body(body)
                    .build();

            // 解析回调请求
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            System.out.println("Parsed transaction: " + transaction);
            // 如果支付成功，修改数据库信息
            if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
                // 处理订单对调
                OrderTypeEnum orderTypeEnum = OrderTypeEnum.getByCode(Integer.parseInt(transaction.getAttach()));
                if (Objects.nonNull(orderTypeEnum)) {
                    switch (orderTypeEnum) {
                        case COUNSELOR -> {
                            ServiceCounselorOrderPo serviceCounselorOrderPo = serviceCounselorOrderMapper.selectById(Long.parseLong(transaction.getOutTradeNo()));
                            serviceCounselorOrderPo.setTransactionId(transaction.getTransactionId());
                            serviceCounselorOrderPo.setPayType(Integer.parseInt(transaction.getAttach()));
                            serviceCounselorOrderPo.setTransactionTime(StringUtils.parseDateTime_2(transaction.getSuccessTime()));
                            serviceCounselorOrderPo.setStatus(ServiceCounselorStatusEnum.SCHEDULED.getCode());
                            Db.saveOrUpdate(serviceCounselorOrderPo);
                        }
                        case GOODS -> {

                        }
                    }
                }
            } else {
                throw new ServiceCounselorOrderException(ServiceCounselorOrderException.PAY_FAIL);
            }
        } catch (Exception e) {
            // 更具体地捕获和处理异常
            throw new ServiceCounselorOrderException(ServiceCounselorOrderException.PAY_FAIL);
        } finally {
            // 确保资源被正确关闭
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return AjaxResult.successMsg();
    }
}
